<template>
  <div 
    ref="containerRef" 
    class="virtual-waterfall-container"
    @scroll="handleScroll"
  >
    <div 
      class="virtual-waterfall-content"
      :style="{ height: `${totalHeight}px` }"
    >
      <div 
        v-for="item in visibleItems" 
        :key="item.id"
        class="virtual-waterfall-item"
        :class="{ 'item-in-view': itemsInView.includes(item.id) }"
        :style="getItemStyle(item.id)"
      >
        <slot name="item" :item="item"></slot>
      </div>
    </div>
    
    <!-- 初始加载状态 -->
    <div v-if="isInitialLoading" class="initial-loading">
      <div class="loading-spinner"></div>
      <span>正在加载精彩内容...</span>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, onMounted, onBeforeUnmount, watch, nextTick } from 'vue';

const props = defineProps({
  items: {
    type: Array,
    required: true
  },
  columns: {
    type: Number,
    default: 2
  },
  estimatedItemHeight: {
    type: Number,
    default: 280
  },
  buffer: {
    type: Number,
    default: 5
  },
  columnGap: {
    type: Number,
    default: 10
  },
  rowGap: {
    type: Number,
    default: 10
  }
});

const emit = defineEmits(['loadMore']);

// 基本状态
const containerRef = ref(null);
const visibleItems = ref([]);
const itemPositions = ref(new Map());
const columnHeights = ref([]);
const totalHeight = ref(0);
const containerWidth = ref(0);
const itemWidth = ref(0);
const isLoadingMore = ref(false);
const isInitialLoading = ref(true);
const itemsInView = ref([]);
const lastScrollPosition = ref(0);
const scrollDirection = ref('down');

// 初始化列高度
const initColumnHeights = () => {
  columnHeights.value = Array(props.columns).fill(0);
};

// 计算项目位置 - 完全重写的布局算法
const calculateItemPositions = () => {
  if (!containerRef.value) return;

  // 重置列高度
  initColumnHeights();

  // 获取容器宽度
  containerWidth.value = containerRef.value.clientWidth;
  
  // 计算每列的宽度（考虑间隙）
  const totalGapWidth = props.columnGap * (props.columns - 1);
  // 减去右边距，确保最右边的项目不会贴近边框
  const rightMargin = 8; 
  // 添加左边距，确保最左边的项目不会贴近边框
  const leftMargin = 8;
  itemWidth.value = (containerWidth.value - totalGapWidth - rightMargin - leftMargin) / props.columns;

  // 创建新的位置Map
  const newPositions = new Map();
  
  // 为每个项目计算位置
  props.items.forEach((item) => {
    // 找出当前最短的列
    const minColumnIndex = columnHeights.value.indexOf(Math.min(...columnHeights.value));
    
    // 计算项目位置，添加左边距
    const left = leftMargin + minColumnIndex * (itemWidth.value + props.columnGap);
    const top = columnHeights.value[minColumnIndex];
    
    // 使用项目的实际高度或估计高度
    const itemHeight = item.height || props.estimatedItemHeight;
    
    // 更新该列的高度
    columnHeights.value[minColumnIndex] += itemHeight + props.rowGap;
    
    // 存储位置信息
    newPositions.set(item.id, {
      left,
      top,
      width: itemWidth.value,
      height: itemHeight
    });
  });
  
  // 更新位置信息
  itemPositions.value = newPositions;
  
  // 更新总高度 - 确保有足够的空间
  totalHeight.value = Math.max(...columnHeights.value);
  
  // 初始加载完成
  if (props.items.length > 0) {
    setTimeout(() => {
      isInitialLoading.value = false;
    }, 500);
  }
};

// 获取项目样式
const getItemStyle = (itemId) => {
  const position = itemPositions.value.get(itemId);
  if (!position) return {};
  
  return {
    left: `${position.left-8}px`,
    top: `${position.top}px`,
    width: `${position.width}px`,
    height: `${position.height}px`
  };
};

// 更新可视项目
const updateVisibleItems = () => {
  if (!containerRef.value) return;

  const scrollTop = containerRef.value.scrollTop;
  const containerHeight = containerRef.value.clientHeight;

  // 确定滚动方向
  scrollDirection.value = scrollTop > lastScrollPosition.value ? 'down' : 'up';
  lastScrollPosition.value = scrollTop;

  // 增加缓冲区
  const topBuffer = props.buffer * props.estimatedItemHeight;
  const bottomBuffer = props.buffer * props.estimatedItemHeight;
  
  // 可视区域的范围(带缓冲区)
  const visibleTop = Math.max(0, scrollTop - topBuffer);
  const visibleBottom = scrollTop + containerHeight + bottomBuffer;

  // 筛选可视项目
  const newVisibleItems = props.items.filter((item) => {
    const position = itemPositions.value.get(item.id);
    if (!position) return false;

    const isVisible = position.top < visibleBottom && 
                     position.top + position.height > visibleTop;
    
    // 如果项目可见，添加到视图中用于动画
    if (isVisible && !itemsInView.value.includes(item.id)) {
      // 延迟添加以创建瀑布效果
      setTimeout(() => {
        if (!itemsInView.value.includes(item.id)) {
          itemsInView.value.push(item.id);
        }
      }, Math.random() * 200);
    }
    
    return isVisible;
  });
  
  visibleItems.value = newVisibleItems;
};

// 滚动处理
const handleScroll = () => {
  if (!containerRef.value) return;
  
  requestAnimationFrame(() => {
    updateVisibleItems();

    // 检查是否需要加载更多
    const { scrollTop, scrollHeight, clientHeight } = containerRef.value;
    const scrollThreshold = scrollHeight - clientHeight - 200; // 提前200px触发
    
    if (scrollTop > scrollThreshold && !isLoadingMore.value) {
      isLoadingMore.value = true;
      emit('loadMore');
      
      // 防止频繁触发
      setTimeout(() => {
        isLoadingMore.value = false;
      }, 1000);
    }
  });
};

// 监听数据变化 - 完全重新计算布局
watch(
  () => props.items,
  (newItems, oldItems) => {
    // 如果是添加了新项目
    if (newItems.length > oldItems.length) {
      // 计算位置
      calculateItemPositions();
      
      // 更新可视项目
      nextTick(() => {
        updateVisibleItems();
      });
    } 
    // 如果是初始加载或数据完全变化
    else if (oldItems.length === 0 || newItems.length !== oldItems.length) {
      calculateItemPositions();
      nextTick(() => {
        updateVisibleItems();
      });
    }
  },
  { deep: true }
);

// 监听项目高度变化
watch(
  () => [...props.items].map(item => item.height),
  () => {
    calculateItemPositions();
    nextTick(() => {
      updateVisibleItems();
    });
  },
  { deep: true }
);

// 监听列数变化
watch(
  () => props.columns,
  () => {
    calculateItemPositions();
    updateVisibleItems();
  }
);

// 优化的resize处理函数
let resizeTimeout = null;
const handleResize = () => {
  if (resizeTimeout) clearTimeout(resizeTimeout);
  
  resizeTimeout = setTimeout(() => {
    calculateItemPositions();
    updateVisibleItems();
  }, 200);
};

// 生命周期钩子
onMounted(() => {
  nextTick(() => {
    calculateItemPositions();
    updateVisibleItems();
  });
  
  window.addEventListener('resize', handleResize);
});

onBeforeUnmount(() => {
  window.removeEventListener('resize', handleResize);
  if (resizeTimeout) clearTimeout(resizeTimeout);
});
</script>

<style scoped>
.virtual-waterfall-container {
  width: 100%;
  height: 100%;
  overflow-y: auto;
  overflow-x: hidden;
  position: relative;
  -webkit-overflow-scrolling: touch;
}

.virtual-waterfall-content {
  position: relative;
  width: 100%;
}

.virtual-waterfall-item {
  position: absolute;
  transition: opacity 0.3s ease, transform 0.3s ease;
  opacity: 0;
  transform: translateY(20px);
  will-change: opacity, transform;
}

.item-in-view {
  opacity: 1;
  transform: translateY(0);
}

.initial-loading {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: #999;
  font-size: 14px;
}

.loading-spinner {
  width: 30px;
  height: 30px;
  border: 3px solid #f3f3f3;
  border-top: 3px solid #ff2442;
  border-radius: 50%;
  margin-bottom: 10px;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}
</style>

